package com.gagakuai.bpm.service.camunda.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.exceptions.ApiException;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

import com.gagakuai.bpm.common.component.PublisherContext;
import com.gagakuai.bpm.common.constants.BpmInsActConstants;
import com.gagakuai.bpm.common.constants.BpmMetaConstants;
import com.gagakuai.bpm.common.enums.BusinessCodeEnum;
import com.gagakuai.bpm.common.enums.OperateStatusEnum;
import com.gagakuai.bpm.common.exception.BpmException;
import com.gagakuai.bpm.dao.mapper.ActHiIdentitylinkMapper;
import com.gagakuai.bpm.dao.mapper.ActHiTaskinstMapper;
import com.gagakuai.bpm.dao.mapper.ActRuIdentitylinkMapper;
import com.gagakuai.bpm.dao.mapper.camunda.*;
import com.gagakuai.bpm.domian.dto.camunda.*;
import com.gagakuai.bpm.domian.entity.ActHiTaskinst;
import com.gagakuai.bpm.domian.entity.camuda.*;
import com.gagakuai.bpm.domian.events.AddInstanceEvent;
import com.gagakuai.bpm.domian.events.RejectTaskEvent;
import com.gagakuai.bpm.domian.events.UpdateStartNodeCreateEvent;
import com.gagakuai.bpm.domian.query.camunda.WorkflowQuery;
import com.gagakuai.bpm.domian.vo.camunda.ActivityNodeVO;
import com.gagakuai.bpm.service.camunda.WorkflowTaskService;
import com.gagakuai.bpm.utils.*;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.ibatis.javassist.compiler.ast.Variable;
import org.camunda.bpm.engine.*;
import org.camunda.bpm.engine.form.StartFormData;
import org.camunda.bpm.engine.form.TaskFormData;
import org.camunda.bpm.engine.history.HistoricActivityInstance;
import org.camunda.bpm.engine.history.HistoricProcessInstance;
import org.camunda.bpm.engine.history.HistoricProcessInstanceQuery;
import org.camunda.bpm.engine.history.HistoricTaskInstance;
import org.camunda.bpm.engine.impl.RepositoryServiceImpl;
import org.camunda.bpm.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.camunda.bpm.engine.impl.persistence.entity.TaskEntity;
import org.camunda.bpm.engine.impl.pvm.process.ActivityImpl;
import org.camunda.bpm.engine.runtime.ActivityInstance;
import org.camunda.bpm.engine.runtime.ProcessInstance;
import org.camunda.bpm.engine.task.Task;
import org.camunda.bpm.engine.variable.VariableMap;
import org.camunda.bpm.engine.variable.Variables;
import org.camunda.bpm.model.bpmn.BpmnModelInstance;
import org.camunda.bpm.model.bpmn.instance.FlowNode;
import org.camunda.bpm.model.bpmn.instance.SequenceFlow;
import org.camunda.bpm.model.xml.instance.DomElement;
import org.camunda.bpm.model.xml.instance.ModelElementInstance;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.sql.Timestamp;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/*
 * bpm
 */
@Service
@Slf4j
public class WorkflowTaskServiceImpl implements WorkflowTaskService, ApplicationContextAware {


    //事件发布器
    @Autowired
    private PublisherContext publisherContext;

    @Resource
    private RuntimeService runtimeService;

    @Resource
    private TaskService taskService;

    @Resource
    private FormService formService;

    @Resource
    private HistoryService historyService;

    @Resource
    private IdentityService identityService;

    @Resource
    private RepositoryService repositoryService;

    @Resource
    private WorkflowTaskMapper workflowTaskMapper;

    @Resource
    private ActHiProcinstMapper actHiProcinstMapper;

    @Resource
    private ActGeBytearrayMapper actGeBytearrayMapper;

    @Resource
    private ActHiCommentMapper actHiCommentMapper;

    @Resource
    private ActRuTaskMapper actRuTaskMapper;

    @Resource
    private ActIdUserMapper userMapper;

    @Resource
    private ActHiActinstMapper actHiActinstMapper;

    @Resource
    private ActHiTaskinstMapper actHiTaskinstMapper;

    @Resource
    private WorkFlowTaskNodeMapper workFlowTaskNodeMapper;

    @Resource
    private ActRuIdentitylinkMapper actRuIdentitylinkMapper;

    @Resource
    private ActHiIdentitylinkMapper actHiIdentitylinkMapper;

    @Resource
    private WorkflowTaskService workflowTaskService;


    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private RedisTemplate redisTemplate;

    /*
     * hmily事务日志
     */
    @Resource
    private HmilyTryLogMapper hmilyTryLogMapper;

    @Resource
    private HmilyConfirmLogMapper hmilyConfirmLogMapper;

    @Resource
    private HmilyCancelLogMapper hmilyCancelLogMapper;


    /*
     * //  @Resource
     * private InformService informService;
     * // @Resource
     * private FilterService filterService;
     * <p>
     * //@Resource
     * private DecisionService decisionService;
     * <p>
     * // @Resource
     * private ManagementService managementService;
     */


    @Override
    public WorkflowFormData getStartFormData(String pdId) {
        if (StringUtils.isBlank(pdId)) {
            throw new ApiException("参数pdId不能为空");
        }
        WorkflowFormData form = new WorkflowFormData();
        StartFormData formData = formService.getStartFormData(pdId);
        form.setProcessId(formData.getProcessDefinition().getId())
                .setProcessKey(formData.getProcessDefinition().getKey())
                .setProcessName(formData.getProcessDefinition().getName())
                .setFormKey(formData.getFormKey())
                .setDeploymentId(formData.getDeploymentId())
                .setFormFields(formData.getFormFields());
        return form;
    }

    @Override
    public WorkflowFormData getTaskFormData(String taskId) {
        WorkflowFormData form = new WorkflowFormData();
        // 查询出的表单字段自动关联variables中的变量值
        TaskFormData taskFormData = formService.getTaskFormData(taskId);
        if (taskFormData == null) {
            return null;
        }

        form.setFormKey(taskFormData.getFormKey())
                .setDeploymentId(taskFormData.getDeploymentId())
                .setProcessId(taskFormData.getTask().getProcessDefinitionId())
                .setFormFields(taskFormData.getFormFields())
                .setTaskId(taskFormData.getTask().getId())
                .setTaskName(taskFormData.getTask().getName());
        return form;
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public String startProcess(String key, WorkflowVariableDto dto) throws Exception {
        List<String> tenantIds = new ArrayList<>();
        if (ObjectUtils.isNotEmpty(dto.getTenantIds())) {
            tenantIds = new ArrayList<>(Arrays.asList(dto.getTenantIds().split(",")));
        }

        Map<String, Object> variables = runtimeService.getVariables("taskId");


        // 设置流程发起人
        if (StringUtils.isNotBlank(dto.getStartUser())) {
            identityService.setAuthentication(dto.getStartUser(), new ArrayList<>(), tenantIds);
        }


        variables.put("assigneeNum", 1);
        dto.setVariables(variables);
        // 启动流程实例
        ProcessInstance instance = runtimeService.startProcessInstanceByKey(key, dto.getBusinessId(), dto.getVariables());

        //启动成功
        String processInstanceId = instance.getProcessInstanceId();

        Long newDate = System.currentTimeMillis() - 1000;

        Date newCreateTime = new Date(newDate);
        //修改第一个节点的时间
        actHiActinstMapper.updateCreateTimeByIns(newCreateTime, processInstanceId);

        //添加实列的ASSIGNEE （办理人）
        actHiActinstMapper.updateAssigneeForStartEventByProcessId(processInstanceId, dto.getStartUser());

        List<ActRuTask> actRuTaskList = actRuTaskMapper.selectByPocInsId(processInstanceId, null);

        for (ActRuTask actRuTask : actRuTaskList) {
            if (Objects.nonNull(actRuTask)) {

                String taskId = actRuTask.getId();
                dto.setAssignee(dto.getStartUser());
                Map<String, Object> variabless = new HashMap<>();
                variables.put("assignee", dto.getStartUser());
                dto.setVariables(variabless);
                taskService.complete(taskId, dto.getVariables());
            }

        }
        String redisKey = BpmMetaConstants.BPM_COMPLETED_TYPE_GLOBAL
                + BpmMetaConstants.REDIS_FILE_KEY_SEPTOR + processInstanceId;

        Map<Object, Object> hmget = redisUtil.hmget(redisKey);


        String originTaskOwnersStr = (String) hmget.get("originTaskOwnersStr");

        String originTaskOwnersStrNotDelegate = (String) hmget.get("originTaskOwnersStrNotDelegate");

        String lastTaskOwnerStr = (String) hmget.get("lastTaskOwnerStr");

        String lastTaskDefKey = (String) hmget.get("lastTaskDefKey");

        String taskDefKey = (String) hmget.get("taskDefKey");


        //初始化 任务拥有者
        if (StringUtils.isEmpty(lastTaskOwnerStr) && StringUtils.isNonEmpty(lastTaskDefKey)) {


            List<HistoricTaskInstance> historyTaskList = historyService.createHistoricTaskInstanceQuery()
                    .processInstanceId(processInstanceId)
                    .taskDefinitionKey(lastTaskDefKey)
                    .list();

            StringBuffer lastTaskOwnerBuffer = new StringBuffer();
            historyTaskList.stream().map(HistoricTaskInstance::getAssignee).forEach(assigne -> {
                lastTaskOwnerBuffer.append(BpmMetaConstants.REDIS_CONDITION_KEY_SEPTOR)
                        .append(assigne);
            });
            hmget.put("lastTaskOwnerStr", lastTaskOwnerBuffer.toString());
        }

        if (StringUtils.isEmpty(originTaskOwnersStr) && StringUtils.isNonEmpty(taskDefKey)) {


            List<HistoricTaskInstance> historyTaskList = historyService.createHistoricTaskInstanceQuery()
                    .processInstanceId(processInstanceId)
                    .taskDefinitionKey(taskDefKey)
                    .list();

            StringBuffer thisTaskOwnerBuffer = new StringBuffer();
            historyTaskList.stream().map(HistoricTaskInstance::getAssignee).forEach(assigne -> {
                thisTaskOwnerBuffer.append(BpmMetaConstants.REDIS_CONDITION_KEY_SEPTOR)
                        .append(assigne);
            });
            hmget.put("originTaskOwnersStr", thisTaskOwnerBuffer.toString());
        }

        if (StringUtils.isEmpty(originTaskOwnersStrNotDelegate) && StringUtils.isNonEmpty(taskDefKey)) {


            List<HistoricTaskInstance> historyTaskList = historyService.createHistoricTaskInstanceQuery()
                    .processInstanceId(processInstanceId)
                    .taskDefinitionKey(taskDefKey)
                    .list();

            StringBuffer thisTaskOwnerBuffer = new StringBuffer();
            historyTaskList.stream().map(HistoricTaskInstance::getAssignee).forEach(assigne -> {
                thisTaskOwnerBuffer.append(BpmMetaConstants.REDIS_CONDITION_KEY_SEPTOR)
                        .append(assigne);
            });
            hmget.put("originTaskOwnersStrNotDelegate", thisTaskOwnerBuffer.toString());
        }

        redisUtil.hmset(redisKey, hmget);

        //发布修改创建时间事件
        UpdateStartNodeCreateEvent updateStartNodeCreateEvent = new UpdateStartNodeCreateEvent(processInstanceId);
        applicationContext.publishEvent(updateStartNodeCreateEvent);
        return processInstanceId;
    }

    @Override
    public List<HistoricProcessInstance> getMyProcessInstances(WorkflowQuery workflowQueryDto) {

        HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery();
        // 根据流程发起人查询
        if (StringUtils.isNotBlank(workflowQueryDto.getStartUser())) {
            query.startedBy(workflowQueryDto.getStartUser());
        }
        // 根据流程名称查询
        if (StringUtils.isNotBlank(workflowQueryDto.getProcessDefinitionName())) {
            query.processDefinitionNameLike("%".concat(workflowQueryDto.getProcessDefinitionName()).concat("%"));
        }
        // 判断流程是否结束
        if (StringUtils.equalsIgnoreCase(workflowQueryDto.getIsFinished(), OperateStatusEnum.Y.name())) {
            query.finished();
        }
        // 分页查询
        return query.list();
//        long total = query.count();
//        PageData<HistoricProcessInstance> pageData = new PageData<>(pageRequest);
//        pageData.setTotal(total).calcPages().setContent(list);
//        return pageData;
    }

    /*
     * 获取流程总数
     *
     * @param key 流程定义key
     */
    @Override
    public String getProcessInstanceNum(String key) {


        List<String> maxBuinessNo = actHiProcinstMapper.selectMaxBuinessByKey(key);

        if (maxBuinessNo == null) {
            return null;
        }

        int maxNo = 0;
        String result = null;
        for (String curBusneKey : maxBuinessNo) {

            String[] splitList = curBusneKey.split(",");

            String businessName = splitList[0];
            String businessKey = splitList[1];
            String curBunessKey = businessKey.substring(1, businessKey.length() - 1);
            String[] split = curBunessKey.split("-");

            String curNo = split[split.length - 1];
            int temp = Integer.parseInt(curNo);
            maxNo = Math.max(maxNo, temp);
            if (maxNo == temp) {
                result = curBusneKey;
            }
        }

        return result;
    }

    @Override
    public WorkflowNodesDto getNodeIds(String proInsId) {
        HistoricProcessInstance hpi = historyService.createHistoricProcessInstanceQuery().processInstanceId(proInsId).singleResult();
        WorkflowNodesDto dto = new WorkflowNodesDto();
        String sql = "SELECT * FROM `act_hi_actinst` where PROC_INST_ID_ = #{proInsId} order by SEQUENCE_COUNTER_ asc";
        List<HistoricActivityInstance> actList = historyService.createNativeHistoricActivityInstanceQuery()
                .sql(sql)
                .parameter("proInsId", proInsId)
                .list();
        BpmnModelInstance bpmnModel = repositoryService.getBpmnModelInstance(hpi.getProcessDefinitionId());
        if (CollectionUtils.isNotEmpty(actList)) {
            for (int i = 0; i < actList.size(); i++) {
                dto.getActIns().add(actList.get(i));
                // 获取该活动的流程图节点
                FlowNode flowNode = bpmnModel.getModelElementById(actList.get(i).getActivityId());
                // 找到该节点的流出箭头元素
                assert flowNode != null;
                Collection<SequenceFlow> sequenceFlows = flowNode.getOutgoing();
                if (i < actList.size() - 1) {
                    HistoricActivityInstance nextAct = actList.get(i + 1);
                    // 判断流出箭头的流入节点是否在这些节点中
                    sequenceFlows.forEach(flow -> {
                        if (flow.getTarget().getId().equals(nextAct.getActivityId())) {
                            dto.getSeqIds().add(flow.getId());
                        }
                    });
                }
            }
        }
        return dto;
    }

    private QueryWrapper<WorkflowTaskEntity> createQueryWrapper(WorkflowQuery condition) {
        QueryWrapper<WorkflowTaskEntity> queryWrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(condition.getTenantId())) {
            queryWrapper.eq("t.TENANT_ID_", condition.getTenantId());
        }
        // 根据任务名称查询
        if (StringUtils.isNotBlank(condition.getTaskName())) {
            queryWrapper.like("t.NAME_", condition.getTaskName());
        }
        // 根据流程名称查询
        if (StringUtils.isNotBlank(condition.getProcessDefinitionName())) {
            queryWrapper.like("t.PROC_DEF_NAME_", condition.getProcessDefinitionName());
        }

        if (StringUtils.isNotBlank(condition.getAssignee())) {
            queryWrapper.eq("t.ASSIGNEE_", condition.getAssignee());
        }
        if (StringUtils.isNotBlank(condition.getOwner())) {
            queryWrapper.eq("t.OWNER_", condition.getOwner());
        }
        return queryWrapper;
    }

    @Override
    public List<WorkflowTaskEntity> getTodoTaskList(WorkflowQuery workflowQueryDto) {

        QueryWrapper<WorkflowTaskEntity> queryWrapper = new QueryWrapper<>();

        if (ObjectUtils.isNotEmpty(workflowQueryDto.getTaskId()) && StringUtils.isNotBlank(workflowQueryDto.getTaskId())) {
            queryWrapper.eq("ID_", workflowQueryDto.getTaskId());
        }

        if (ObjectUtils.isNotEmpty(workflowQueryDto.getProcessDefinitionName()) && StringUtils.isNotBlank(workflowQueryDto.getProcessDefinitionName())) {
            queryWrapper.eq("PROC_DEF_NAME_", workflowQueryDto.getProcessDefinitionName());
        }

        queryWrapper.or(ObjectUtils.isNotEmpty(workflowQueryDto.getOwner()),
                qw -> qw.eq("OWNER_", workflowQueryDto.getOwner()));

        queryWrapper.or(ObjectUtils.isNotEmpty(workflowQueryDto.getAssignee()),
                qw -> qw.eq("ASSIGNEE_", workflowQueryDto.getAssignee()));

        boolean isEmpty = StringUtils.isBlank(workflowQueryDto.getCandidateUsers())
                && StringUtils.isBlank(workflowQueryDto.getCandidateGroups());
        if (!isEmpty) {
            queryWrapper.or(qw -> {
                if (StringUtils.isNotBlank(workflowQueryDto.getCandidateUsers())) {
                    qw.or().exists(String.format("select ID_ from ACT_HI_IDENTITYLINK " +
                            "where TASK_ID_ = t.ID_ and TYPE_ = 'candidate' " +
                            "and USER_ID_ = '%s'", workflowQueryDto.getCandidateUsers()));
                }

                if (StringUtils.isNotBlank(workflowQueryDto.getCandidateGroups())) {
                    String groupIds = StringUtils.getSqlInStringByArray(workflowQueryDto.getCandidateGroups());
                    qw.or().exists(String.format("select ID_ from ACT_HI_IDENTITYLINK " +
                            "where TASK_ID_ = t.ID_ and TYPE_ = 'candidate' " +
                            "and GROUP_ID_ in (%s)", groupIds));
                }
            });
        }

        queryWrapper.orderByDesc("START_TIME_");
        return workflowTaskMapper.listTodoTaskByPage(queryWrapper);
    }

    @Override
    public List<WorkflowTaskEntity> getCompleteTaskList(WorkflowQuery workflowQueryDto) {
        QueryWrapper<WorkflowTaskEntity> queryWrapper = createQueryWrapper(workflowQueryDto);

        if (StringUtils.isNotBlank(workflowQueryDto.getCandidateGroups()) || StringUtils.isNotBlank(workflowQueryDto.getCandidateUsers())) {
            queryWrapper.and(eq -> {
                if (StringUtils.isNotBlank(workflowQueryDto.getCandidateUsers())) {
                    eq.or().exists(String.format("select ID_ from ACT_HI_IDENTITYLINK " +
                            "where TASK_ID_ = t.ID_ and TYPE_ = 'candidate' " +
                            "and USER_ID_ = '%s'", workflowQueryDto.getCandidateUsers()));
                }

                if (StringUtils.isNotBlank(workflowQueryDto.getCandidateGroups())) {
                    String groupIds = StringUtils.getSqlInStringByArray(workflowQueryDto.getCandidateGroups());
                    eq.or().exists(String.format("select ID_ from ACT_HI_IDENTITYLINK " +
                            "where TASK_ID_ = t.ID_ and TYPE_ = 'candidate' " +
                            "and GROUP_ID_ in (%s)", groupIds));
                }
            });
        }
        return workflowTaskMapper.listCompleteTaskByPage(queryWrapper);
    }

    @Override
    public void claimTask(String taskId, String claimUser) {
        taskService.claim(taskId, claimUser);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delegateTask(String taskId, String delegationUser, ActHiComment actHiComment) {
        // 将 taskId 任务委托给 delegationUser，
        // 引擎会自动将owner设置为当前的assignee，
        // 将assignee设置为delegationUser
        // 针对委托，不会增加一条记录，所有需要自己插入一条新的记录
        ActHiActinst old = actHiActinstMapper.selectByTaskId(taskId).get(0);
        String oldId = old.getId();
        Date startTime = old.getStartTime();
        ActHiTaskinst oldTask = actHiTaskinstMapper.selectByPrimaryKey(taskId);
        /*
         *
         *
         * todo 在委托的时候，需要修改taskOrign 人用于加签的bug
         *
         *
         */
        StringBuffer globalTaskBuild = new StringBuffer();
        globalTaskBuild.append(BpmMetaConstants.BPM_COMPLETED_TYPE_GLOBAL)
                .append(BpmMetaConstants.REDIS_FILE_KEY_SEPTOR)
                .append(oldTask.getProcInstId());

        Map<Object, Object> hmget = redisUtil.hmget(globalTaskBuild.toString());

        //先进行委托。然后再记录操作
        taskService.delegateTask(taskId, delegationUser);

        //更新当前的人,
        List<String> newCompletedMan = actRuTaskMapper.selectCurTaskOwnerListForDelagate(old.getProcInstId());

        StringBuffer originTaskOwnersStrBuffer = new StringBuffer();

        for (String newCompletedP : newCompletedMan) {
            if (ObjectUtils.isNotEmpty(newCompletedP)) {
                originTaskOwnersStrBuffer.append(BpmMetaConstants.REDIS_CONDITION_KEY_SEPTOR)
                        .append(newCompletedP);
            }
        }
        hmget.put("originTaskOwnersStr", originTaskOwnersStrBuffer.toString());
        redisUtil.hmset(globalTaskBuild.toString(), hmget);
        /*
         *
         *  委托记录 -- 记录操作 todo  需要更改taskId吗？ 更改后，需要同步这个taskId 去评论表里面设置taskId
         *
         *    todo 在这里，需要确保存在redis中的返回上一步的人是正确的，在回写之后
         *
         */
        ActHiActinst newData = old;
        newData.setId(IDgenerateUtils.nextIdStr());
        String newTaskId = IDgenerateUtils.nextIdStr();
        newData.setTaskId(newTaskId);
        newData.setStartTime(new Timestamp(startTime.getTime() + 100l));
        newData.setEndTime(new Timestamp(System.currentTimeMillis() - 100l));
        //计算委托时间
        newData.setDuration(newData.getEndTime().getTime() - newData.getStartTime().getTime());
        newData.setActInstState(BpmInsActConstants.ACT_INS_RETURN_RELEGTE);
        //设置任务拥有人
        StringBuffer keyBuild = new StringBuffer();
        keyBuild.append(BpmMetaConstants.TASK_ORIGIN_OWNER)
                .append(taskId);
        String taskOnwer = (String) redisUtil.get(keyBuild.toString());

        String owner = taskOnwer.split(":")[1];
        newData.setOwner(owner);
        actHiActinstMapper.insertSelective(newData);

        //插入一条任务历史表
        ActHiTaskinst newTaskIdHi = actHiTaskinstMapper.selectByPrimaryKey(taskId);
        //设置新的id
        newTaskIdHi.setId(newTaskId);
        newTaskIdHi.setOwner(owner);
        //设置assinge;
        newTaskIdHi.setAssignee(delegationUser);
        actHiTaskinstMapper.insertSelective(newTaskIdHi);

        //todo  委托意见
        actHiComment.setId(IDgenerateUtils.nextIdStr());
        actHiComment.setTaskId(newData.getTaskId());
        actHiComment.setTime(new Timestamp(System.currentTimeMillis()));
        actHiComment.setProcInstId(newData.getProcInstId());
        actHiComment.setRootProcInstId(newData.getProcInstId());
        actHiCommentMapper.insertSelective(actHiComment);

        actHiIdentitylinkMapper.deleteRecordByTaskId(taskId);

        //委托成功后，修改时间为这条任务的时间
       /* ActHiActinst updateAct = new ActHiActinst();
        updateAct.setStartTime(new Timestamp());
        updateAct.setId(oldId);
        updateAct.setOwner(owner);
        actHiActinstMapper.updateByPrimaryKeySelective(updateAct);*/
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public String completeTask(String taskId, WorkflowVariableDto dto, UserInfo userInfo) {
        // 获取完成前任务
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (ObjectUtils.isEmpty(task)) {
            return "没有查找到当前任务";
        }

        // 对共享任务的处理
        if (StringUtils.isBlank(task.getAssignee())) {
            if (ObjectUtils.isEmpty(dto.getVariables().get("assignee"))) {
                return "当前任务为共享任务，请先设置执行人";
            } else {
                claimTask(taskId, dto.getVariables().get("assignee").toString());
            }
        } else {
            if (!userInfo.getUserId().equals(task.getAssignee())) {
                return "当前任务执行人与任务绑定人不相符";
            }
        }

        // 完成任务填写的备注
        if (StringUtils.isNotBlank(dto.getReason()) && StringUtils.isNotBlank(task.getProcessInstanceId())) {
            taskService.createComment(task.getId(), task.getProcessInstanceId(), dto.getReason());
        }

        // 完成当前任务
        taskService.complete(taskId, dto.getVariables());

        //记录操作
        actHiActinstMapper.updateInsStateByTaskId(BpmInsActConstants.ACT_INS_NORMAL, taskId);
        //更新结束时间多加1S
        // actHiTaskinstMapper.updateEndTime(task.getProcessInstanceId(), 1);
        //修改end节点的时间
        ActHiActinst actHiActinst = workFlowTaskNodeMapper.selectEndNodeByProcess(task.getProcessInstanceId());
        if (ObjectUtils.isNotEmpty(actHiActinst)) {
            actHiTaskinstMapper.updateEndTimeByActId(actHiActinst.getId(), 1);
        }
        return null;
    }


    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public String withDrawTask(String taskId, WorkflowVariableDto dto, UserInfo userInfo) {
        // 获取完成前任务
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (ObjectUtils.isEmpty(task)) {
            return "没有查找到当前任务";
        }

        // 对共享任务的处理
        if (StringUtils.isBlank(task.getAssignee())) {
            if (ObjectUtils.isEmpty(dto.getVariables().get("assignee"))) {
                return "当前任务为共享任务，请先设置执行人";
            } else {
                claimTask(taskId, dto.getVariables().get("assignee").toString());
            }
        } else {
            if (!userInfo.getUserId().equals(task.getAssignee())) {
                return "当前任务执行人与任务绑定人不相符";
            }
        }

        // 完成任务填写的备注
        if (StringUtils.isNotBlank(dto.getReason()) && StringUtils.isNotBlank(task.getProcessInstanceId())) {
            taskService.createComment(task.getId(), task.getProcessInstanceId(), dto.getReason());
        }

        // 完成当前任务
        taskService.complete(taskId, dto.getVariables());

        //记录操作
        actHiActinstMapper.updateInsStateByTaskId(BpmInsActConstants.ACT_INS_WITH_DRAW, taskId);


        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public String rejectTask(String taskId, WorkflowVariableDto dto, UserInfo userInfo) {
        // 获取完成前任务
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (ObjectUtils.isEmpty(task)) {
            return "没有查找到当前任务";
        }
        // 对共享任务的处理
        if (StringUtils.isBlank(task.getAssignee())) {
            if (ObjectUtils.isEmpty(dto.getVariables().get("assignee"))) {
                return "当前任务为共享任务，请先设置执行人";
            } else {
                claimTask(taskId, dto.getVariables().get("assignee").toString());
            }
        } else {
            if (!userInfo.getUserId().equals(task.getAssignee())) {
                return "当前任务执行人与任务绑定人不相符";
            }
        }

        // 完成任务填写的备注
        if (StringUtils.isNotBlank(dto.getReason()) && StringUtils.isNotBlank(task.getProcessInstanceId())) {
            taskService.createComment(task.getId(), task.getProcessInstanceId(), dto.getReason());
        }

        //首先根据processIns 找到所有的ru_task_id; 然后在回退了以后，再删除数据
        List<ActRuTask> ruTaskList = workflowTaskService.getRuTaskByProcIns(task.getProcessInstanceId());
        List<String> taskIdList = ruTaskList.stream().map(ActRuTask::getId).collect(Collectors.toList());
        // 完成当前任务
        taskService.complete(taskId, dto.getVariables());

        //记录操作 -- 修改一下end_time
        actHiActinstMapper.updateInsStateByTaskId(BpmInsActConstants.ACT_INS_REJECT, taskId);
        //修改taskHi的Owner
        ActHiTaskinst updateOnwerPo = new ActHiTaskinst();
        updateOnwerPo.setId(taskId);
        updateOnwerPo.setOwner((String) dto.getVariables().get("taskOriginOwner"));


        if (StringUtils.isNotEmpty(updateOnwerPo.getOwner())) {
            actHiTaskinstMapper.updateByPrimaryKeySelective(updateOnwerPo);
        }
        // 修改一下截止记录的start_time && end_time
        actHiCommentMapper.updateActTaskEndTimeByProcessId(task.getProcessInstanceId());


        //删除
        //删除ACT_HI_ACTINST中的历史
        taskIdList.remove(taskId);
        if (CollectionUtils.isNotEmpty(taskIdList)) {
            actHiActinstMapper.deleteHiByTaskList(taskIdList);
        }

        //todo 发布一个事件出去,如果没有找state = 1的，就自己创建一条。
        RejectTaskEvent.RejectTaskEventEventData rejectTaskEventEventData = new RejectTaskEvent.RejectTaskEventEventData();
        rejectTaskEventEventData.setRejectTaskId(taskId);
        rejectTaskEventEventData.setProcessId(task.getProcessInstanceId());
        RejectTaskEvent rejectTaskEvent = new RejectTaskEvent(rejectTaskEventEventData);
        //发布事件
        publisherContext.publish(rejectTaskEvent);

        //修改状态
        ActHiProcinst updateStatePo = new ActHiProcinst();
        updateStatePo.setId(task.getProcessInstanceId());
        updateStatePo.setState("REJECTED");
        actHiProcinstMapper.updateByPrimaryKeySelective(updateStatePo);

        return null;
    }

    @Override
    public CamundaHighLineDTO getHighlightNode(String processInsId, String authorId) {
        Set<String> finished = new HashSet<>();
        // 存放我【authorId】完成
        Set<String> mineFinished = new HashSet<>();
        //保存高亮的连线
        Set<String> highLine = new HashSet<>();
        Set<String> unFinished = new HashSet<>();

        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                .processInstanceId(processInsId)
                .singleResult();
        if (historicProcessInstance != null) {
            // 已完成节点
            List<HistoricActivityInstance> finishedList = historyService.createHistoricActivityInstanceQuery()
                    .processInstanceId(processInsId)
                    .orderByHistoricActivityInstanceStartTime()
                    .finished()
                    .asc()
                    .list();

            finishedList.forEach(item -> finished.add(item.getActivityId()));

            // 待完成节点
            List<HistoricActivityInstance> unFinishedList = historyService.createHistoricActivityInstanceQuery()
                    .processInstanceId(processInsId)
                    .unfinished()
                    .orderByHistoricActivityInstanceStartTime()
                    .asc().list();

            unFinishedList.forEach(item -> unFinished.add(item.getActivityId()));

            List<HistoricTaskInstance> historicTaskInstanceList = historyService.createHistoricTaskInstanceQuery()
                    .processInstanceId(processInsId)
                    .taskAssignee(authorId)
                    .finished()
                    .list();
            historicTaskInstanceList.forEach(item -> mineFinished.add(item.getTaskDefinitionKey()));

            String key = historicProcessInstance.getProcessDefinitionId();
            assert StringUtils.isNotBlank(key);
            BpmnModelInstance bpmnModelInstance = repositoryService.getBpmnModelInstance(key);
            assert bpmnModelInstance != null;
            int finishedNum = finishedList.size();
            //循环 已完成的节点
            for (int i = 0; i < finishedNum; i++) {
                HistoricActivityInstance historicActivityInstance = finishedList.get(i);
                //根据 任务key 获取 bpmn元素
                ModelElementInstance modelElementInstance = bpmnModelInstance.getModelElementById(historicActivityInstance.getActivityId());
                //转换成 flowNode流程节点 才能获取到 输出线 和输入线
                FlowNode flowNode = (FlowNode) modelElementInstance;
                Collection<SequenceFlow> sequenceFlowCollection = flowNode.getOutgoing();
                sequenceFlowCollection.forEach(item -> {
                    String tarId = item.getTarget().getId();
                    // 已完成
                    for (HistoricActivityInstance stepInstance : finishedList) {
                        String activityId = stepInstance.getActivityId();
                        if (tarId.equals(activityId) && historicActivityInstance.getEndTime().equals(stepInstance.getStartTime())) {
                            highLine.add(item.getId());
                        }
                    }

                    // 待完成
                    for (HistoricActivityInstance setpUnFinish : unFinishedList) {
                        //循环待节点 和当前完成节点的向下分支比对
                        String finxId = setpUnFinish.getActivityId();
                        if (tarId.equals(finxId) && historicActivityInstance.getEndTime().equals(setpUnFinish.getStartTime())) {
                            highLine.add(item.getId());
                        }
                    }
                });
            }
        }

        CamundaHighLineDTO camundaHighLineDTO = new CamundaHighLineDTO();
        camundaHighLineDTO.setFinished(finished);
        camundaHighLineDTO.setUnfinished(unFinished);
        camundaHighLineDTO.setMine(mineFinished);
        camundaHighLineDTO.setHighLine(highLine);

        return camundaHighLineDTO;
    }

    /*
     * 驳回并返回到起点
     *
     * @param processInstanceId 流程实例ID
     * @param taskId            任务ID
     * @param reason            原因
     */
    @Override
    public boolean reject(String processInstanceId, String taskId, String reason, int step) {
        Task task = taskService.createTaskQuery().processInstanceId(processInstanceId).taskId(taskId).singleResult();
        if (task != null) {
            ActivityInstance activityInstance = runtimeService.getActivityInstance(processInstanceId);
            if (activityInstance != null) {
                List<HistoricActivityInstance> historicActivityInstanceList = historyService.createHistoricActivityInstanceQuery()
                        .processInstanceId(processInstanceId)
                        .executionId(task.getExecutionId())
                        .activityType("userTask")
                        .finished()
                        .orderByHistoricActivityInstanceEndTime()
                        .desc().list();

                historicActivityInstanceList = historicActivityInstanceList.stream().filter(it -> !it.getActivityId().equals(task.getTaskDefinitionKey())).collect(Collectors.toList());

                if (historicActivityInstanceList.size() > 0) {
                    HistoricActivityInstance first = historicActivityInstanceList.get(step);
                    String toActId = first.getActivityId();
                    String assignee = first.getAssignee();

                    Map<String, Object> taskVariable = new HashMap<>();
                    //设置当前处理人
                    taskVariable.put("assignee", assignee);

                    // 填写拒绝的原因
                    taskService.createComment(task.getId(), processInstanceId, reason);

                    runtimeService.createProcessInstanceModification(processInstanceId)
                            //关闭相关任务
                            .cancelActivityInstance(getInstanceIdForActivity(activityInstance, task.getTaskDefinitionKey()))
                            .setAnnotation("进行了驳回到" + step + "任务节点操作")
                            //启动目标活动节点
                            .startBeforeActivity(toActId)
                            //流程的可变参数赋值
                            .setVariables(taskVariable)
                            .execute();

                    return true;
//                    List<Task> _taskList = taskService.createTaskQuery().processInstanceId(processInstanceId).list();
//
//                    if(ObjectUtils.isNotEmpty(_taskList)){
//                        for(Task item: _taskList){
//                            if(item.getTaskDefinitionKey().equals(toActId)){
//                                taskService.setAssignee(item.getId(), assignee);
//                                return true;
//                            }
//                        }
//                    }
                }
            }
        }
        return false;
    }

    @Override
    public List<CommentDto> tableContent(String processInstanceId) {
        return workflowTaskMapper.tableContent(processInstanceId);
    }

    /*
     * 手动知会
     *
     * @param taskId    产生需要知会的任务
     * @param assignees 需要知会的用户ID，多个以逗号隔开
     * @return 返回执行情况的字符串
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String handleInfo(String taskId, String assignees) {
        if (StringUtils.isBlank(taskId)) {
            return "任务ID不能为空";
        }

        if (StringUtils.isBlank(assignees)) {
            return "知会人不能为空";
        }

        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (ObjectUtils.isEmpty(task)) {
            return "没有查询到当前任务";
        }

        String[] assigneeArray = assignees.split(",");
        for (String assignee : assigneeArray) {
            TaskEntity taskEntity = new TaskEntity();
            taskEntity.setId(UUID.randomUUID().toString());
            taskEntity.setRevision(1);
            taskEntity.setExecutionId(task.getExecutionId());
            taskEntity.setProcessInstanceId(task.getProcessInstanceId());
            taskEntity.setProcessDefinitionId(task.getProcessDefinitionId());
            taskEntity.setName("手动知会");
            taskEntity.setParentTaskId(task.getParentTaskId());
            taskEntity.setDescription("手动知会");
            taskEntity.setTaskDefinitionKey(task.getTaskDefinitionKey());
            taskEntity.setPriority(50);
            taskEntity.setCreateTime(new Date());
            taskEntity.setSuspensionState(1);
            taskEntity.setAssignee(assignee.trim());
            taskEntity.insert();
        }

        return "";
    }

    @Override
    public String readed(String taskId, String reason) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();

        if (ObjectUtils.isEmpty(task)) {
            return "没有找到当前任务";
        }

        taskService.complete(taskId);
        taskService.createComment(taskId, task.getProcessInstanceId(), reason);
        return "";
    }

    @Override
    public List<ActivityNodeVO> getActivityNodeList(String procId) {
        List<ActivityNodeVO> activityNodeVOList = new ArrayList<>();
        if (StringUtils.isBlank(procId)) {
            return activityNodeVOList;
        }

        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(procId).singleResult();
        if (ObjectUtils.isEmpty(historicProcessInstance)) {
            return activityNodeVOList;
        }

        BpmnModelInstance bpmnModelInstance = repositoryService.getBpmnModelInstance(historicProcessInstance.getProcessDefinitionId());
        if (ObjectUtils.isEmpty(bpmnModelInstance)) {
            return activityNodeVOList;
        }

        List<DomElement> domElementList = bpmnModelInstance.getDocument().getRootElement().getChildElements();
        if (ObjectUtils.isEmpty(domElementList)) {
            return activityNodeVOList;
        }

        DomElement domElement = domElementList.stream().filter(it -> "process".equals(it.getLocalName())).findFirst().orElse(null);
        if (ObjectUtils.isEmpty(domElement)) {
            return activityNodeVOList;
        }

        activityNodeVOList.addAll(ActivityNodeUtils.createActivityNodeBySubProcessElement(domElement));
        return activityNodeVOList;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean inform(Inform inform) {
        Task task = judgeTask(inform.getTaskId());
        if (ObjectUtils.isEmpty(task)) {
            return false;
        }

        ActivityInstance activityInstance = runtimeService.getActivityInstance(task.getProcessInstanceId());
        if (ObjectUtils.isEmpty(activityInstance)) {
            return false;
        }

        List<HistoricActivityInstance> historicActivityInstanceList = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(task.getProcessInstanceId()).list();
        if (ObjectUtils.isEmpty(historicActivityInstanceList)) {
            return false;
        }

        log.info("ActivityInstance:{}", activityInstance);
        List<ActiInstEntity> list = new ArrayList<>();
        List<HiTaskInstEntity> listHiTaskInstEntity = new ArrayList<>();
        final String activityId = "Activity_inform";
        inform.getUserIdList().forEach(id -> {
            String actInstId = UUID.randomUUID().toString();
            String taskId = UUID.randomUUID().toString();

            String procDefKey = historicActivityInstanceList.get(0).getProcessDefinitionKey();
            String procDefId = historicActivityInstanceList.get(0).getProcessDefinitionId();
            String rootProcInsId = historicActivityInstanceList.get(0).getRootProcessInstanceId();
            String procInsId = task.getProcessInstanceId();
            String executionId = task.getExecutionId();

            ActiInstEntity actiInstEntity = new ActiInstEntity();
            actiInstEntity.setId(String.join(":", activityId, actInstId));
            actiInstEntity.setParentActInstId(historicActivityInstanceList.get(0).getParentActivityInstanceId());
            actiInstEntity.setProcDefKey(procDefKey);
            actiInstEntity.setProcDefId(procDefId);
            actiInstEntity.setRootProcInstId(rootProcInsId);
            actiInstEntity.setProcInstId(procInsId);
            actiInstEntity.setExecutionId(executionId);
            actiInstEntity.setActId(activityId);
            actiInstEntity.setTaskId(taskId);
            actiInstEntity.setActName("手动知会");
            actiInstEntity.setActType("serviceTask");
            actiInstEntity.setAssignee(id);
            actiInstEntity.setStartTime(DateUtils.getCurrentTime());

            list.add(actiInstEntity);

            HiTaskInstEntity hiTaskInstEntity = new HiTaskInstEntity();
            hiTaskInstEntity.setId(taskId);
            hiTaskInstEntity.setTaskDefKey(activityId);
            hiTaskInstEntity.setProcDefKey(procDefKey);
            hiTaskInstEntity.setProcDefId(procDefId);
            hiTaskInstEntity.setRootProcInstId(rootProcInsId);
            hiTaskInstEntity.setProcInstId(procInsId);
            hiTaskInstEntity.setExecutionId(executionId);
            hiTaskInstEntity.setActInstId(String.join(":", activityId, actInstId));
            hiTaskInstEntity.setName("手动知会");
            hiTaskInstEntity.setParentTaskId(task.getParentTaskId());
            hiTaskInstEntity.setDescription("手动知会");
            hiTaskInstEntity.setOwner(null);
            hiTaskInstEntity.setAssignee(id);
            hiTaskInstEntity.setStartTime(DateUtils.getCurrentTime());
            hiTaskInstEntity.setPriority(50);

            listHiTaskInstEntity.add(hiTaskInstEntity);
        });

        int count1 = workflowTaskMapper.intoActInst(list);
        int count2 = workflowTaskMapper.intoHiTaskInst(listHiTaskInstEntity);

        return count1 == count2;
    }

    private Task judgeTask(String taskId) {
        return taskService.createTaskQuery().taskId(taskId).singleResult();
    }

    protected int checkProcessInstanceState(String procId) {
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(procId).singleResult();
        if (ObjectUtils.isEmpty(processInstance)) {
            return 5;
        }

        if (processInstance.isEnded()) {
            return 6;
        }

        return 0;
    }

    protected int checkProcessStarter(String procId, UserInfo userInfo) {
        ProcInstEntity procInstEntity = workflowTaskMapper.queryProcInstEntityById(procId);
        if (ObjectUtils.isEmpty(procInstEntity) || !procInstEntity.getStartUserId().equals(userInfo.getUserId())) {
            return 8;
        }
        return 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int fetchBack(String procId, UserInfo userInfo) {
        try {
            // 判断当前流程的状态
            int state = checkProcessInstanceState(procId);
            if (state != 0) {
                return state;
            }

            // 判断是否有任务
            List<Task> taskList = taskService.createTaskQuery().processInstanceId(procId).list();
            if (ObjectUtils.isEmpty(taskList)) {
                return 1;
            }

            // 判断当前执行人是否为流程发起人
            state = checkProcessStarter(procId, userInfo);
            if (state != 0) {
                return state;
            }

            String processInstanceId = taskList.get(0).getProcessInstanceId();
            ActivityInstance activityInstance = runtimeService.getActivityInstance(processInstanceId);
            // 判断当前实例是否为空
            if (ObjectUtils.isEmpty(activityInstance) || ObjectUtils.isEmpty(activityInstance.getChildActivityInstances())) {
                return 7;
            }

            // 判断是否处于第一个用户任务节点
            List<HistoricActivityInstance> historicActivityInstanceList = historyService.createHistoricActivityInstanceQuery()
                    .processInstanceId(processInstanceId)
                    .activityType("userTask")
                    .unfinished().orderByHistoricActivityInstanceStartTime()
                    .asc().list();
            if (ObjectUtils.isEmpty(historicActivityInstanceList) ||
                    historicActivityInstanceList.get(0).getActivityId().equals(activityInstance.getChildActivityInstances()[0].getActivityId())) {
                return 3;
            }

            String toActId = historicActivityInstanceList.get(0).getActivityId();
            String assignee = historicActivityInstanceList.get(0).getAssignee();
            //设置当前处理人
            Map<String, Object> taskVariable = new HashMap<>();
            taskVariable.put("assignee", assignee);

            runtimeService.createProcessInstanceModification(processInstanceId)
                    //关闭相关任务
                    .cancelActivityInstance(getInstanceIdForActivity(activityInstance, taskList.get(0).getTaskDefinitionKey()))
                    .setAnnotation("进行了取回到节点操作")
                    //启动目标活动节点
                    .startBeforeActivity(toActId)
                    //流程的可变参数赋值
                    .setVariables(taskVariable)
                    .execute();

            // 删除任务表其它任务
            List<String> taskIdList = new ArrayList<>();
            List<String> actIdList = new ArrayList<>();
            for (int i = 1; i < taskList.size(); i++) {
                taskIdList.add(taskList.get(i).getId());
                actIdList.add(getInstanceIdForActivity(activityInstance, taskList.get(i).getTaskDefinitionKey()));
            }

            if (ObjectUtils.isNotEmpty(taskIdList) && ObjectUtils.isNotEmpty(actIdList)) {
                // 删除ACT_RU_EXECUTION 表中的实例
                workflowTaskMapper.deleteTaskByIdArray(taskIdList);
                // 删除ACT_RU_EXECUTION数据
                workflowTaskMapper.deleteExecutionByProcInstIdAndActInstIdArray(processInstanceId, actIdList);
                // 更新ACT_HI_TASKINST表
                workflowTaskMapper.updateHiTaskInstByIdArray(taskIdList, DateUtils.getCurrentTime());
                // 更新ACT_HI_ACTINST数据
                workflowTaskMapper.updateHiActInstById(actIdList, DateUtils.getCurrentTime());
            }

            return 0;
        } catch (Exception e) {
            log.error("取回异常：{}", e.getMessage());
            return 4;
        }
    }

    /*
     * 退回到上一步流程:放在评论里面
     *
     * @param processInstanceId
     * @param actHiComment
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public int processDrawToLastStep(String processInstanceId, ActHiComment actHiComment) throws Exception {

        // 根据流程实例 id 获取当前任务
        List<Task> curTaskList = taskService.createTaskQuery()
                .processInstanceId(processInstanceId)
                .active()
                .list();
        Task activeTask = curTaskList.get(0);

        HistoricTaskInstance taskInstance = historyService.createHistoricTaskInstanceQuery()
                .taskId(activeTask.getId())
                .singleResult();

        String activeTaskId = activeTask.getId();

        //首先根据processIns 找到所有的ru_task_id; 然后在回退了以后，再删除数据
        List<ActRuTask> ruTaskList = workflowTaskService.getRuTaskByProcIns(actHiComment.getProcInstId());
        List<String> taskIdList = ruTaskList.stream().map(ActRuTask::getId).collect(Collectors.toList());

        //从历史表里面记录数据上一一节点的数据
        StringBuffer bpmredisKey = new StringBuffer(BpmMetaConstants.BPM_COMPLETED_TYPE_GLOBAL);
        bpmredisKey.append(BpmMetaConstants.REDIS_FILE_KEY_SEPTOR).append(processInstanceId);


        Set<String> lastOwnerList = new ConcurrentSkipListSet<>();

        Map<Object, Object> hmget = redisUtil.hmget(bpmredisKey.toString());

        // 获取流程定义
        ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService).getDeployedProcessDefinition(taskInstance.getProcessDefinitionId());

        // 获取当前活动
        ActivityImpl currentActivity = processDefinitionEntity.findActivity(taskInstance.getTaskDefinitionKey());


        // 获取上一个活动
        ActivityImpl lastActivity = getLastActivityImpl(processInstanceId, processDefinitionEntity);

        //重新获取上一步的任务定义
        String lastTaskDef = getLastTaskDef(processInstanceId);

        //获取上一步任务的人
        lastOwnerList = getLastOwner(processInstanceId,lastTaskDef);


        int index = 0;
        //  回到上一步
        for (String lastOwnerName : lastOwnerList) {

            if (StringUtils.isEmpty(lastOwnerName)) {

                continue;

            }
            runtimeService.createProcessInstanceModification(processInstanceId)
                    .cancelAllForActivity(currentActivity.getActivityId())
                    .startBeforeActivity(lastActivity.getActivityId())
                    .setVariable("denyReason", "测试退回" + ++index)
                    .setVariable("assignee", lastOwnerName)
                    .execute();
        }

        //设置已经返回上一步
        hmget.put("isExecuteLastStep",1);
        redisUtil.hmset(bpmredisKey.toString(),hmget);

        //添加意见
        //设置流根Id
        UUID uuid = UUID.randomUUID();
        actHiComment.setId(uuid.toString());
        actHiComment.setRootProcInstId(processInstanceId);
        actHiComment.setProcInstId(processInstanceId);
        actHiComment.setAction("ReturnLastStep");
        if (actHiComment.getMessage() != null) {
            actHiComment.setFullMsg(actHiComment.getMessage().getBytes());
        } else {
            actHiComment.setFullMsg(null);
        }
        // actHiComment.setFullMsg(resaon.getBytes());
        actHiComment.setTime(new Date());
        //todo 做一个TaskId
        actHiComment.setTaskId(activeTask.getId());
        actHiCommentMapper.insertSelective(actHiComment);

        //设置退回上一步处理人 --在流转节点表里面处理
        String assigene = actHiComment.getUserId();

        actHiActinstMapper.updateAssigneeByTaskId(assigene, activeTask.getId());

        //修改状态
        actHiActinstMapper.updateInsStateByTaskId(BpmInsActConstants.ACT_INS_RETURN_LAST_STEP, activeTask.getId());

        //修改taskHi
        ActHiTaskinst oldTask = new ActHiTaskinst();
        oldTask.setId(activeTaskId);
        //设置人
        oldTask.setOwner(actHiComment.getTaskOriginOwner());
        actHiTaskinstMapper.updateByPrimaryKeySelective(oldTask);

        //设置退回上一步处理人 --在任务历史表里处理
        workFlowTaskNodeMapper.updateAssigneByTaskId(assigene, activeTask.getId());

        //第二步 进行针对加签的情况，需要进行删除当前已经活跃的task
        workflowTaskService.deleteRutaaskNumByProcessIns(taskIdList);
        //删除历史
        //workflowTaskService.deleteHitaaskNumByProcessIns(taskIdList);
        //删除actHi --排除当前条数据
        taskIdList.remove(activeTask.getId());
        if (CollectionUtils.isNotEmpty(taskIdList)) {
            actHiActinstMapper.deleteHiByTaskList(taskIdList);
        }

        return 0;
    }

    public List<String> getLastOwner(String processInstanceId) {

        String redisKey = BpmMetaConstants.BPM_COMPLETED_TYPE_GLOBAL
                + BpmMetaConstants.REDIS_FILE_KEY_SEPTOR + processInstanceId;

        Map<Object, Object> hmget = redisUtil.hmget(redisKey);

        String lastTaskDefKey = (String) hmget.get("lastTaskDefKey");

        String addInstancesStr = (String) hmget.get("addInstancesStr");

        Object isExecuteLastStep = hmget.get("isExecuteLastStep");

        //是否执行返回上一步
        Integer isExecuteLastStepInt = 0;
        if (ObjectUtils.isNotEmpty(isExecuteLastStep)) {

            if (isExecuteLastStep instanceof Integer) {

                isExecuteLastStepInt = (Integer) isExecuteLastStep;
            } else if (isExecuteLastStep instanceof String) {

                isExecuteLastStepInt = new Integer(isExecuteLastStepInt);
            }
        }


        //执行过退回上一步 数据就从上一步拿取
        if (1 == isExecuteLastStepInt) {

        }

        //所有的任务人
        List<String> orignWithAddInsaceUserList = new ArrayList<>();
        if (StringUtils.isNonEmpty(lastTaskDefKey)) {


            List<HistoricTaskInstance> historyTaskList = historyService.createHistoricTaskInstanceQuery()
                    .processInstanceId(processInstanceId)
                    .taskDefinitionKey(lastTaskDefKey)
                    .list();

            for (HistoricTaskInstance historicTaskInstance : historyTaskList) {

                String curTaskOwner = StringUtils.isNonEmpty(historicTaskInstance.getOwner()) ? historicTaskInstance.getOwner()
                        : historicTaskInstance.getAssignee();
                orignWithAddInsaceUserList.add(curTaskOwner);
            }
        }

        List<String> addInsaceList = new ArrayList<>();
        //获取所有的加签人
        if (StringUtils.isNonEmpty(addInstancesStr)) {
            String[] addInstanceArr = addInstancesStr.split(BpmMetaConstants.REDIS_CONDITION_KEY_SEPTOR);
            List<String> list = Arrays.asList(addInstanceArr);
            addInsaceList.addAll(list);
        }

        List<String> result = new ArrayList<>();
        //移除加签人
        result = orignWithAddInsaceUserList.stream().filter(
                b -> addInsaceList.stream().noneMatch(id -> Objects.equals(b, id))).collect(Collectors.toList());


        return result;

    }

    /*
     * @param lastTaskDefKey
     * @param processInstanceId 流程定义key
     * @param lastTaskDefKey    上一步定义key
     * @return {@link List< String>}
     * @Author houhong
     * @Description //TODO
     * @Date 4:36 下午 2022/7/18
     */
    public Set<String > getLastOwner(String processInstanceId, String lastTaskDefKey) {

        String redisKey = BpmMetaConstants.BPM_COMPLETED_TYPE_GLOBAL
                + BpmMetaConstants.REDIS_FILE_KEY_SEPTOR + processInstanceId;

        Map<Object, Object> hmget = redisUtil.hmget(redisKey);



        String  addInstancesStr = (String) hmget.get("addInstancesStr");

        //所有的任务人
        List<String> orignWithAddInsaceUserList = new ArrayList<>();
        if (StringUtils.isNonEmpty(lastTaskDefKey)) {


            List<HistoricTaskInstance> historyTaskList = historyService.createHistoricTaskInstanceQuery()
                    .processInstanceId(processInstanceId)
                    .taskDefinitionKey(lastTaskDefKey)
                    .list();

            for (HistoricTaskInstance historicTaskInstance : historyTaskList) {

                String curTaskOwner = StringUtils.isNonEmpty(historicTaskInstance.getOwner()) ? historicTaskInstance.getOwner()
                        : historicTaskInstance.getAssignee();
                orignWithAddInsaceUserList.add(curTaskOwner);
            }
        }

        List<String> addInsaceList = new ArrayList<>();
        //获取所有的加签人
        if (StringUtils.isNonEmpty(addInstancesStr)) {
            String[] addInstanceArr = addInstancesStr.split(BpmMetaConstants.REDIS_CONDITION_KEY_SEPTOR);
            List<String> list = Arrays.asList(addInstanceArr);
            addInsaceList.addAll(list);
        }

        List<String> result = new ArrayList<>();
        //移除加签人
        result = orignWithAddInsaceUserList.stream().filter(
                b -> addInsaceList.stream().noneMatch(id -> Objects.equals(b, id))).collect(Collectors.toList());

        Set<String >  realResultSet = new ConcurrentSkipListSet<>(result);

        return realResultSet;

    }


    public String getLastTaskDef(String processInstanceId) {

        // 根据流程实例 id 获取当前任务
        Task activeTask = taskService.createTaskQuery()
                .processInstanceId(processInstanceId)
                .active()
                .list().get(0);


        // TODO: 2022/7/15  直接从redis中获取 -- 直接数据里获取
        /*String lastTaskDefRedisKey = BpmMetaConstants.BPM_COMPLETED_TYPE_GLOBAL
                + BpmMetaConstants.REDIS_FILE_KEY_SEPTOR + processInstanceId;

        if (redisUtil.hasKey(lastTaskDefRedisKey)) {

            Map<Object, Object> hmget = redisUtil.hmget(lastTaskDefRedisKey);
            String lastTaskDefKey = (String) hmget.get(BpmMetaConstants.BPM_LAST_TASK_DEFKEY);

            Object isExecuteLastStep = hmget.get("isExecuteLastStep");

            //是否执行过返回上一步
            Integer isExecuteLastStepInt = 0;
            if (ObjectUtils.isNotEmpty(isExecuteLastStep)) {

                if (isExecuteLastStep instanceof Integer) {

                    isExecuteLastStepInt = (Integer) isExecuteLastStep;
                } else if (isExecuteLastStep instanceof String) {

                    isExecuteLastStepInt = new Integer(isExecuteLastStepInt);
                }
            }

            if (1 != isExecuteLastStepInt && StringUtils.isNonEmpty(lastTaskDefKey)) {
                // 获取当前活动
                return lastTaskDefKey;
            }
        }*/


        // 新建一个有序不重复集合
        LinkedHashSet linkedHashSet = new LinkedHashSet();
        // 获取当前的任务节点
        String activeTaskStr = activeTask.getTaskDefinitionKey();
        String backTask = "";

        List<HistoricTaskInstance> historicTaskInstances = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(processInstanceId)
                .orderByHistoricActivityInstanceStartTime()
                .asc().list();

        for (HistoricTaskInstance historicTaskInstance : historicTaskInstances) {

            linkedHashSet.add(historicTaskInstance.getTaskDefinitionKey());
        }
        if (linkedHashSet.size() == 0) {
            return null;
        }

        // 遍历到当前的任务节点后,取上一次遍历的值
        Iterator<String> iterator = linkedHashSet.iterator();
        while (iterator.hasNext()) {
            String nowTask = iterator.next();
            if (StringUtils.equals(nowTask, activeTaskStr)) {
                break;
            }
            backTask = nowTask;
        }
        if (StringUtils.isNonEmpty(backTask)) {

            // 获取当前活动
            return backTask;

        } else if (StringUtils.isEmpty(backTask)) {

            iterator = linkedHashSet.iterator();
            //获取下一个节点
            while (iterator.hasNext()) {
                String nowTask = iterator.next();
                if (StringUtils.equals(nowTask, activeTaskStr)) {
                    iterator.hasNext();
                    String next = iterator.next();
                    backTask = next;
                    break;
                }
            }
            // 获取当前活动
            return backTask;
        }
        return null;


    }

    public ActivityImpl getLastActivityImpl(String processInstanceId, ProcessDefinitionEntity processDefinitionEntity) {

        // 根据流程实例 id 获取当前任务
        Task activeTask = taskService.createTaskQuery()
                .processInstanceId(processInstanceId)
                .active()
                .list().get(0);


        // TODO: 2022/7/15  直接从redis中获取
        String lastTaskDefRedisKey = BpmMetaConstants.BPM_COMPLETED_TYPE_GLOBAL
                + BpmMetaConstants.REDIS_FILE_KEY_SEPTOR + processInstanceId;

        /*if (redisUtil.hasKey(lastTaskDefRedisKey)) {

            Map<Object, Object> hmget = redisUtil.hmget(lastTaskDefRedisKey);
            String lastTaskDefKey = (String) hmget.get(BpmMetaConstants.BPM_LAST_TASK_DEFKEY);

            Object isExecuteLastStep = hmget.get("isExecuteLastStep");

            //是否执行过返回上一步
            Integer isExecuteLastStepInt = 0;
            if (ObjectUtils.isNotEmpty(isExecuteLastStep)) {

                if (isExecuteLastStep instanceof Integer) {

                    isExecuteLastStepInt = (Integer) isExecuteLastStep;
                } else if (isExecuteLastStep instanceof String) {

                    isExecuteLastStepInt = new Integer(isExecuteLastStepInt);
                }
            }

            if (1 != isExecuteLastStepInt && StringUtils.isNonEmpty(lastTaskDefKey)) {
                // 获取当前活动
                return processDefinitionEntity.findActivity(lastTaskDefKey);
            }
        }*/


        // 新建一个有序不重复集合
        LinkedHashSet linkedHashSet = new LinkedHashSet();
        // 获取当前的任务节点
        String activeTaskStr = activeTask.getTaskDefinitionKey();
        String backTask = "";

        List<HistoricTaskInstance> historicTaskInstances = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(processInstanceId)
                .orderByHistoricActivityInstanceStartTime()
                .asc().list();

        for (HistoricTaskInstance historicTaskInstance : historicTaskInstances) {

            linkedHashSet.add(historicTaskInstance.getTaskDefinitionKey());
        }
        if (linkedHashSet.size() == 0) {
            return null;
        }

        // 遍历到当前的任务节点后,取上一次遍历的值
        Iterator<String> iterator = linkedHashSet.iterator();
        while (iterator.hasNext()) {
            String nowTask = iterator.next();
            if (StringUtils.equals(nowTask, activeTaskStr)) {
                break;
            }
            backTask = nowTask;
        }
        if (StringUtils.isNonEmpty(backTask)) {

            // 获取当前活动
            return processDefinitionEntity.findActivity(backTask);

        } else if (StringUtils.isEmpty(backTask)) {

            iterator = linkedHashSet.iterator();
            //获取下一个节点
            while (iterator.hasNext()) {
                String nowTask = iterator.next();
                if (StringUtils.equals(nowTask, activeTaskStr)) {
                    iterator.hasNext();
                    String next = iterator.next();
                    backTask = next;
                    break;
                }
            }
            // 获取当前活动
            return processDefinitionEntity.findActivity(backTask);
        }
        return null;
    }

    /*
     *  退回重填
     *
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public int processDrawToStart(String processInstanceId, ActHiComment actHiComment) {


        //String processInstanceId = "49b521ac-9f50-11ec-8d1f-5254000c17ac";
        //String processInstanceId = "37f9f9f4-9f72-11ec-8d1f-5254000c17ac";
        // 根据流程实例 id 获取当前任务
        Task activeTask = taskService.createTaskQuery()
                .processInstanceId(processInstanceId)
                .active()
                .list().get(0);
        HistoricTaskInstance taskInstance = historyService.createHistoricTaskInstanceQuery()
                .taskId(activeTask.getId())
                .singleResult();

        String activeTaskId = activeTask.getId();

        //首先根据processIns 找到所有的ru_task_id; 然后在回退了以后，再删除数据
        List<ActRuTask> ruTaskList = workflowTaskService.getRuTaskByProcIns(actHiComment.getProcInstId());
        List<String> taskIdList = ruTaskList.stream().map(ActRuTask::getId).collect(Collectors.toList());

        // 获取流程定义
        ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService).getDeployedProcessDefinition(taskInstance.getProcessDefinitionId());

        // 获取当前活动
        ActivityImpl currentActivity = processDefinitionEntity.findActivity(taskInstance.getTaskDefinitionKey());

        //从历史表里面记录数据上一一节点的数据
        StringBuffer bpmredisKey = new StringBuffer(BpmMetaConstants.BPM_COMPLETED_TYPE_GLOBAL);
        bpmredisKey.append(BpmMetaConstants.REDIS_FILE_KEY_SEPTOR).append(processInstanceId);
        Map<Object, Object> hmget = redisUtil.hmget(bpmredisKey.toString());
        String lastOwner = (String) hmget.get(BpmMetaConstants.BPM_CUR_LAST_TASK_OWNER_KEY);

        log.info("#任务发起人{}#", lastOwner);
        // List<String> lastOwnerList = Arrays.asList(lastOwner.split(BpmMetaConstants.REDIS_CONDITION_KEY_SEPTOR));
        // 获取起始活动
        List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery()
                .activityType("userTask")
                .processInstanceId(processInstanceId)
                .finished()
                .orderByHistoricActivityInstanceEndTime()
                .asc()
                .list();
        if (historicActivityInstances.size() == 0) {
            return 1;
        }
        ActivityImpl lastActivity = processDefinitionEntity.findActivity(historicActivityInstances.get(0).getActivityId());


        int index = 0;


        // 退回至起点 -- todo ？这里是第一个userTask --没有回到流程发起人 ==再试一试
        runtimeService.createProcessInstanceModification(processInstanceId)
                .cancelAllForActivity(currentActivity.getActivityId())
                .startBeforeActivity(lastActivity.getActivityId())
                .setVariable("denyReason", "测试退回" + ++index)
                .execute();

        //添加意见
        //设置流根Id
        UUID uuid = UUID.randomUUID();
        actHiComment.setId(uuid.toString());
        actHiComment.setRootProcInstId(processInstanceId);
        actHiComment.setProcInstId(processInstanceId);
        actHiComment.setAction("AddComment");
        if (actHiComment.getMessage() == null) {
            actHiComment.setFullMsg(actHiComment.getMessage().getBytes());
        } else {
            actHiComment.setFullMsg(null);
        }
        // actHiComment.setFullMsg(resaon.getBytes());
        actHiComment.setTime(new Date());
        //todo 做一个TaskId
        actHiComment.setTaskId(activeTask.getId());
        actHiCommentMapper.insertSelective(actHiComment);


        //设置退回上一步处理人 --在流转节点表里面处理
        String assigene = actHiComment.getUserId();
        actHiActinstMapper.updateAssigneeByTaskId(assigene, activeTask.getId());

        //修改状态 --todo
        actHiActinstMapper.updateInsStateByTaskId(BpmInsActConstants.ACT_INS_RE_DO, activeTask.getId());

        //设置退回上一步处理人 --在任务历史表里处理
        workFlowTaskNodeMapper.updateAssigneByTaskId(assigene, activeTask.getId());

        //修改taskHi
        ActHiTaskinst oldTask = new ActHiTaskinst();
        oldTask.setId(activeTaskId);
        //设置人
        oldTask.setOwner(actHiComment.getTaskOriginOwner());
        actHiTaskinstMapper.updateByPrimaryKeySelective(oldTask);

        //设置退回上一步处理人 --在任务历史表里处理
        workFlowTaskNodeMapper.updateAssigneByTaskId(assigene, activeTask.getId());

        //第二步 进行针对加签的情况，需要进行删除当前已经活跃的task
        workflowTaskService.deleteRutaaskNumByProcessIns(taskIdList);
        //删除历史
        //workflowTaskService.deleteHitaaskNumByProcessIns(taskIdList);
        //删除actHi --排除当前条数据
        taskIdList.remove(activeTask.getId());
        if (CollectionUtils.isNotEmpty(taskIdList)) {
            actHiActinstMapper.deleteHiByTaskList(taskIdList);
        }


        return 0;
    }


    /*
     *  取回
     *
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public int processReturn(String processInstanceId, ActHiComment actHiComment) {

        // 根据流程实例 id 获取当前任务
        Task activeTask = taskService.createTaskQuery()
                .processInstanceId(processInstanceId)
                .active()
                .list().get(0);
        HistoricTaskInstance taskInstance = historyService.createHistoricTaskInstanceQuery()
                .taskId(activeTask.getId())
                .singleResult();


        //获取之前的记录
        ActHiActinst old = actHiActinstMapper.selectByTaskId(activeTask.getId()).get(0);
        Date oldStartTime = old.getStartTime();

        //首先根据processIns 找到所有的ru_task_id; 然后在回退了以后，再删除数据
        List<ActRuTask> ruTaskList = workflowTaskService.getRuTaskByProcIns(actHiComment.getProcInstId());
        List<String> taskIdList = ruTaskList.stream().map(ActRuTask::getId).collect(Collectors.toList());

        // 获取流程定义
        ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService).getDeployedProcessDefinition(taskInstance.getProcessDefinitionId());

        // 获取当前活动
        ActivityImpl currentActivity = processDefinitionEntity.findActivity(taskInstance.getTaskDefinitionKey());

        //从历史表里面记录数据上一一节点的数据
        StringBuffer bpmredisKey = new StringBuffer(BpmMetaConstants.BPM_COMPLETED_TYPE_GLOBAL);
        bpmredisKey.append(BpmMetaConstants.REDIS_FILE_KEY_SEPTOR).append(processInstanceId);
        Map<Object, Object> hmget = redisUtil.hmget(bpmredisKey.toString());
        String lastOwner = (String) hmget.get(BpmMetaConstants.BPM_CUR_LAST_TASK_OWNER_KEY);

        log.info("#任务发起人{}#", lastOwner);
        // List<String> lastOwnerList = Arrays.asList(lastOwner.split(BpmMetaConstants.REDIS_CONDITION_KEY_SEPTOR));
        // 获取起始活动
        List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery()
                .activityType("userTask")
                .processInstanceId(processInstanceId)
                .finished()
                .orderByHistoricActivityInstanceEndTime()
                .asc()
                .list();
        if (historicActivityInstances.size() == 0) {
            return 1;
        }
        ActivityImpl lastActivity = processDefinitionEntity.findActivity(historicActivityInstances.get(0).getActivityId());


        int index = 0;


        // 退回至起点 -- todo ？这里是第一个userTask --没有回到流程发起人 ==再试一试
        runtimeService.createProcessInstanceModification(processInstanceId)
                .cancelAllForActivity(currentActivity.getActivityId())
                .startBeforeActivity(lastActivity.getActivityId())
                .setVariable("denyReason", "测试退回" + ++index)
                .execute();

        //添加意见
        //设置流根Id
        UUID uuid = UUID.randomUUID();
        actHiComment.setId(uuid.toString());
        actHiComment.setRootProcInstId(processInstanceId);
        actHiComment.setProcInstId(processInstanceId);
        actHiComment.setAction("AddComment");
        if (actHiComment.getMessage() == null) {
            actHiComment.setFullMsg(actHiComment.getMessage().getBytes());
        } else {
            actHiComment.setFullMsg(null);
        }
        // actHiComment.setFullMsg(resaon.getBytes());
        actHiComment.setTime(new Date());
        //todo 做一个TaskId
        actHiComment.setTaskId(activeTask.getId());
        actHiCommentMapper.insertSelective(actHiComment);


        //设置退回上一步处理人 --在流转节点表里面处理
        String assigene = actHiComment.getUserId();
        actHiActinstMapper.updateAssigneeByTaskId(assigene, activeTask.getId());

        //先删除自己加的记录
        //workflowTaskService.deleteHitaaskNumByProcessIns(taskIdList);
        //删除actHi --排除当前条数据
        taskIdList.remove(activeTask.getId());
        if (CollectionUtils.isNotEmpty(taskIdList)) {
            actHiActinstMapper.deleteHiByTaskList(taskIdList);
        }


        //然后再记录一条自己需要的数据
        ActHiActinst returnRecord = new ActHiActinst();
        BeanUtils.copyProperties(old, returnRecord);
        String selfAddActTaskId = IDgenerateUtils.nextIdStr();
        returnRecord.setId(IDgenerateUtils.nextIdStr());
        returnRecord.setStartTime(new Timestamp(oldStartTime.getTime()));
        returnRecord.setEndTime(new Timestamp(System.currentTimeMillis() - 1000l));
        returnRecord.setDuration(returnRecord.getEndTime().getTime() - returnRecord.getStartTime().getTime());
        returnRecord.setActInstState(BpmInsActConstants.ACT_INS_RETURN);
        returnRecord.setAssignee(actHiComment.getTaskOriginOwner());
        returnRecord.setTaskId(selfAddActTaskId);

        //记录操作
        actHiActinstMapper.insertSelective(returnRecord);

        //向任务历史表里面插入一条数据
        ActHiTaskinst oldTask = new ActHiTaskinst();
        oldTask.setId(selfAddActTaskId);
        oldTask.setStartTime(new Timestamp(System.currentTimeMillis()));
        //设置人
        oldTask.setOwner(actHiComment.getTaskOriginOwner());
        actHiTaskinstMapper.insertSelective(oldTask);

        return 0;
    }

    @Override
    public String getHighlight(String processInstanceId) {

        List<Task> taskList = taskService.createTaskQuery()
                .processInstanceId(processInstanceId)
                .active()
                .list();


        if (CollectionUtils.isEmpty(taskList)) {
            return null;
        }
        Task activeTask = taskList.get(0);
        return activeTask.getTaskDefinitionKey();

    }

    /*
     * 加签
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public String addInstance(String processInstanceId, WorkflowVariableDto dto) throws Exception {

        // 整个流程的流程实例Id
        //String processInstanceId = "d0a284f3-af8e-11ea-88c4-000ec6dd34b8";
        // 子流程节点的Id，在流程图中查看，此为固定值（一般起一个正规的名字，本例是自动生成的随机名）
        String activityId = null;

        Task activeTask = taskService.createTaskQuery()
                .processInstanceId(processInstanceId)
                .active()
                .list().get(0);

        //加签之前先设置

        //originTaskOwnersStrNotDelegate
        //从数据库里面查
        StringBuffer stringBuilder = new StringBuffer();
        String redisKey = BpmMetaConstants.BPM_COMPLETED_TYPE_GLOBAL
                + BpmMetaConstants.REDIS_FILE_KEY_SEPTOR + processInstanceId;
        Map<Object, Object> hmget = redisUtil.hmget(redisKey);
        List<String> list = actRuTaskMapper.selectCurTaskOwnerList(processInstanceId);

        if (ObjectUtils.isEmpty(hmget.get(BpmMetaConstants.BPM_CUR_CUR_TASK_OWNER_NOT_DELEAGTE_KEY))) {
            list.stream().forEach(cur -> {
                stringBuilder.append(BpmMetaConstants.REDIS_CONDITION_KEY_SEPTOR)
                        .append(cur);
            });
            log.info("#原来的任务拥有者(非委托){}#", stringBuilder.toString());

            hmget.put(BpmMetaConstants.BPM_CUR_CUR_TASK_OWNER_NOT_DELEAGTE_KEY, stringBuilder.toString());
            //将本次任务拥有者发步上去
            redisUtil.hmset(redisKey, hmget);
        }

        //添加taskHi
        ActHiTaskinst taskHiRecord = new ActHiTaskinst();
        BeanUtils.copyProperties(activeTask, taskHiRecord);
        //先查处本条任务的原来数据--然后记录起来
        Set<String> startOwnerSet = redisTemplate.keys(BpmMetaConstants.TASK_ORIGIN_OWNER + "*");

        ActHiActinst oldAct = actHiActinstMapper.selectByTaskId(activeTask.getId()).get(0);

        Map<String, Object> variables = dto.getVariables();

        String assignee = dto.getAssignee();


        List<String> addInstanceList = (ArrayList<String>) variables.get(BpmMetaConstants.ADD_INSTANCE_LIST);

        List<String> curTaskOwnerList = actRuTaskMapper.selectCurTaskOwnerListForDelagate(processInstanceId);

        List<String> intersection = getIntersection(addInstanceList, curTaskOwnerList);

        if (CollectionUtils.isNotEmpty(intersection)) {

            throw new BpmException(BusinessCodeEnum.ADD_INSTANCE_HAS_EXITED);
        }
        //任务拥有者
        String taskOwener = activeTask.getAssignee();

        log.info("#当前任务拥有者,{},加签任务办理人:{}#", taskOwener, assignee);

        //查询任务原来的人
        List<String> orignList = actRuTaskMapper.selectCurTaskOwnerList(activeTask.getProcessInstanceId());
        activityId = activeTask.getTaskDefinitionKey();

        Integer runTaskNumByIns = actRuTaskMapper.selecRunNumByIns(processInstanceId);

        Thread.sleep(500);
        for (String addInstacne : addInstanceList) {
            runtimeService.createProcessInstanceModification(processInstanceId)
                    .startBeforeActivity(activityId)
                    .setVariable("assigneeNum", runTaskNumByIns)
                    .setVariable("assignee", addInstacne)
                    .execute();
        }


        List<String> addTaskKeyList = new ArrayList<>();
        startOwnerSet.stream().forEach(cur -> {
            String result = (String) redisUtil.get(cur);
            addTaskKeyList.add(result.split(":")[0]);
        });

        //成功后修改taskInk为assignee
        List<ActRuTask> actRuTaskList = actRuTaskMapper.selectLastByInsd(processInstanceId, activeTask.getCreateTime(), addTaskKeyList);

      /*  actRuIdentitylinkMapper.updateAssigneeByTaskId(actRuTask.getId(), assignee);

        //修改历史表
        actHiIdentitylinkMapper.updateAssigneeByTaskId(actRuTask.getId(), assignee);*/

        // //todo 修改 使用雪花算法保证id唯一性
        String selfAddActTaskId = IDgenerateUtils.nextIdStr();
        oldAct.setId(IDgenerateUtils.nextIdStr());
        oldAct.setStartTime(new Timestamp(System.currentTimeMillis() + 100l));
        oldAct.setEndTime(new Timestamp(System.currentTimeMillis() + 100l));
        oldAct.setActInstState(BpmInsActConstants.ACT_INS_RETURN_ADD_SIGNED);
        oldAct.setAssignee(assignee);
        oldAct.setTaskId(selfAddActTaskId);
        oldAct.setAssignee((String) variables.get("owner"));
        //设置oldOnwer
        oldAct.setOwner((String) variables.get("taskOriginOwner"));
        //记录操作
        actHiActinstMapper.insertSelective(oldAct);


        taskHiRecord.setId(selfAddActTaskId);
        taskHiRecord.setOwner((String) variables.get("taskOriginOwner"));
        taskHiRecord.setStartTime(new Timestamp(System.currentTimeMillis()));
        actHiTaskinstMapper.insertSelective(taskHiRecord);

        //todo 需要记录加签评论;
        ActHiComment addInstanceComment = new ActHiComment();
        addInstanceComment.setId(IDgenerateUtils.nextIdStr());
        addInstanceComment.setTaskId(selfAddActTaskId);
        addInstanceComment.setTime(new Date());
        addInstanceComment.setMessage(dto.getReason());
        if (addInstanceComment.getMessage() != null) {
            addInstanceComment.setFullMsg(dto.getReason().getBytes());
        }
        addInstanceComment.setUserId(oldAct.getAssignee());
        addInstanceComment.setProcInstId(oldAct.getProcInstId());
        addInstanceComment.setType("addInstance");
        addInstanceComment.setRootProcInstId(oldAct.getProcInstId());
        //插入评论
        actHiCommentMapper.insertSelective(addInstanceComment);


        //发布 加签事件
        AddInstanceEvent.AddInstanceEventData addInstanceEventData = new AddInstanceEvent.AddInstanceEventData();
        StringBuffer stringBuffer = new StringBuffer();

        orignList.stream().forEach(orign -> {
            stringBuffer.append(BpmMetaConstants.REDIS_CONDITION_KEY_SEPTOR).append(orign);
        });

        //获取加签人
        Set<String> endOwnerSet = redisTemplate.keys(BpmMetaConstants.TASK_ORIGIN_OWNER + "*");
        //求差集
        List<String> addtaskKey = endOwnerSet.stream().filter(
                b -> startOwnerSet.stream().noneMatch(taskId -> Objects.equals(b, taskId))).collect(Collectors.toList());

        List<ActHiTaskinst> addTaskactHiTaskinstList = new ArrayList<>();
        //修改加签拥有人
        addtaskKey.stream().forEach(cur -> {

            String taskIdAndOwner = (String) redisUtil.get(cur);
            String[] split = taskIdAndOwner.split(":");
            String taskId = split[0];
            String owner = split[1];
            ActHiTaskinst newAct = new ActHiTaskinst();
            newAct.setOwner(owner);
            newAct.setId(taskId);
            addTaskactHiTaskinstList.add(newAct);
        });
        //入库
        actHiTaskinstMapper.updateAddTaskOwnerBatch(addTaskactHiTaskinstList);

        addInstanceEventData.setOriginTaskOwnersStr(stringBuffer.toString());
        addInstanceEventData.setAssigneeList(addInstanceList);
        addInstanceEventData.setProcessId(processInstanceId);
        addInstanceEventData.setActRuTask(actRuTaskList);
        addInstanceEventData.setTaskOwner(taskOwener);
        addInstanceEventData.setCurAddTaskOwner((String) variables.get("taskOriginOwner"));
        AddInstanceEvent addInstanceEvent = new AddInstanceEvent(addInstanceEventData);
        publisherContext.publish(addInstanceEvent);


        return processInstanceId;
    }

    /*
     * 根据流程实列获取当前活跃的实列数目
     *
     * @param processId
     */
    @Override
    public Integer getRutaaskNumByProcessIns(String processId, String taskDefKey) {


        List<ActRuTask> actRuTasks = actRuTaskMapper.selectByPocInsId(processId, taskDefKey);

        if (Objects.nonNull(actRuTasks)) {
            return actRuTasks.size();
        }
        return 0;
    }

    /*
     * 根据流程实列删除当前活跃的实列数目
     *
     * @param processId
     */
    @Override
    public Integer deleteRutaaskNumByProcessIns(String processId) {

        return actRuTaskMapper.deleteByProsIns(processId);
    }

    /*
     * 根据流程实列删除当前活跃的实列数目
     *
     * @param processIdList
     */
    @Override
    public Integer deleteRutaaskNumByProcessIns(List<String> processIdList) {

        return actRuTaskMapper.deleteByProsInsList(processIdList);
    }

    /*
     * 根据流程实列获取档当前所有的List
     *
     * @param procInstId
     */
    @Override
    public List<ActRuTask> getRuTaskByProcIns(String procInstId) {


        return actRuTaskMapper.selectByPocInsId(procInstId, null);
    }

    /*
     * 根据任务id删除历史记录
     *
     * @param taskIdList
     */
    @Override
    public int deleteHitaaskNumByProcessIns(List<String> taskIdList) {

        return actHiProcinstMapper.deleteTaskList(taskIdList);
    }

    /*
     * 根据任务id获取数量
     *
     * @param taskId
     */
    @Override
    public int getNumByTaskId(String taskId) {

        ActRuTask actRuTask = actRuTaskMapper.selectByPrimaryKey(taskId);

        if (Objects.nonNull(actRuTask)) {
            return 1;
        }
        return 0;
    }

    /*
     * ge
     *
     * @param taskId
     */
    @Override
    public String getTaskDefKeyBytaskId(String taskId) {

        String taskDefKey = actRuTaskMapper.selectTaskDefKeyBytaskId(taskId);
        return taskDefKey;
    }


    /*
     * 要写此功能代码，首先来整理下思路，此功能需要做那那些事。
     * 验证。 具体要验证什么呢？包含当前流程实例状态、当前执行人是否为流程发起人、验证当前活动实例、
     * 取消产生的任务 查找此流程产生的任务并取消
     * 删除此流程实例
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int withDraw(String procId, UserInfo userInfo) throws Exception {
        int state = checkProcessInstanceState(procId);
        if (state != 0) {
            return state;
        }

        List<Task> taskList = taskService.createTaskQuery().processInstanceId(procId).list();
        if (CollectionUtils.isEmpty(taskList)) {
            return 1;
        }

        // 判断当前执行人是否为流程发起人
        state = checkProcessStarter(procId, userInfo);
        if (state != 0) {
            return state;
        }

        Task task = taskList.get(0);

        //获取之前的记录
        ActHiActinst old = actHiActinstMapper.selectByTaskId(task.getId()).get(0);
        List<HistoricActivityInstance> historicActivityInstanceList = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(task.getProcessInstanceId())
                .activityType("userTask")
                // .finished().orderByHistoricActivityInstanceEndTime()
                .orderByHistoricActivityInstanceEndTime()
                .asc().list();

        if (historicActivityInstanceList == null || historicActivityInstanceList.isEmpty()) {
            return 2;
        }

        ActivityInstance activityInstance = runtimeService.getActivityInstance(task.getProcessInstanceId());
        String toActId = historicActivityInstanceList.get(0).getActivityId();
        String assignee = historicActivityInstanceList.get(0).getAssignee();
        Map<String, Object> taskVariable = new HashMap<>();


        //设置当前处理人
        taskVariable.put("assignee", userInfo.getUserName());

        runtimeService.createProcessInstanceModification(task.getProcessInstanceId())
                //关闭相关任务
                .cancelActivityInstance(getInstanceIdForActivity(activityInstance, task.getTaskDefinitionKey()))
                .setAnnotation("进行了撤回到节点操作")
                //启动目标活动节点
                .startBeforeActivity(toActId)
                //流程的可变参数赋值
                .setVariables(taskVariable)
                .execute();

        runtimeService.deleteProcessInstance(task.getProcessInstanceId(), String.format("%s 用户执行了撤回操作", userInfo.getUserName()));


        //先删除多余的自己加的记录
        actHiActinstMapper.deleteMoreRecordProceIns(old.getProcInstId());

        //然后再记录一条自己需要的数据
        ActHiActinst withDrawRecord = new ActHiActinst();
        BeanUtils.copyProperties(old, withDrawRecord);
        String selfAddActTaskId = IDgenerateUtils.nextIdStr();
        withDrawRecord.setId(IDgenerateUtils.nextIdStr());
        withDrawRecord.setStartTime(new Timestamp(System.currentTimeMillis() + 100l));
        withDrawRecord.setEndTime(new Timestamp(System.currentTimeMillis() + 1000l));
        withDrawRecord.setActInstState(BpmInsActConstants.ACT_INS_WITH_DRAW);
        withDrawRecord.setAssignee(assignee);
        withDrawRecord.setTaskId(selfAddActTaskId);

        String assingeName = userInfo.getUserId() != null ? userInfo.getUserId() : userInfo.getUserName();
        withDrawRecord.setAssignee(assingeName);
        withDrawRecord.setOwner(assingeName);
        //记录操作
        actHiActinstMapper.insertSelective(withDrawRecord);

        //向任务历史表里面插入一条数据
        ActHiTaskinst oldTask = new ActHiTaskinst();
        oldTask.setId(selfAddActTaskId);
        oldTask.setStartTime(new Timestamp(System.currentTimeMillis()));
        //设置人
        oldTask.setOwner(userInfo.getTaskOriginOwner());
        actHiTaskinstMapper.insertSelective(oldTask);


        return 0;
    }


    protected String getInstanceIdForActivity(ActivityInstance activityInstance, String activityId) {
        ActivityInstance instance = getChildInstanceForActivity(activityInstance, activityId);
        if (instance != null) {
            return instance.getId();
        }
        return null;
    }

    protected ActivityInstance getChildInstanceForActivity(ActivityInstance activityInstance, String activityId) {
        if (activityId.equals(activityInstance.getActivityId())) {
            return activityInstance;
        }
        for (ActivityInstance childInstance : activityInstance.getChildActivityInstances()) {
            ActivityInstance instance = getChildInstanceForActivity(childInstance, activityId);
            if (instance != null) {
                return instance;
            }
        }
        return null;
    }


    /*
     * 查询待办任务
     *
     * @param workflowQueryDto 查询条件
     * @return 我的任务
     */
    @Override
    public IPage<WorkflowTaskEntityNew> getTodoTaskListByUser(WorkflowQuery workflowQueryDto) {

        String assignee = workflowQueryDto.getAssignee();

        List<String> caniteGroupList = userMapper.selectCaniteGroupList(assignee);

        StringBuilder stringBuilder = new StringBuilder();

        for (int index = 0; index < caniteGroupList.size(); index++) {
            String caniteGroup = caniteGroupList.get(index);

            if (index == caniteGroupList.size() - 1) {
                stringBuilder.append(caniteGroup);
            } else {
                stringBuilder.append(caniteGroup).append(",");
            }

        }
        workflowQueryDto.setCandidateGroups(stringBuilder.toString());
        int pageNumber = workflowQueryDto.getPageNumber();
        int pageSize = workflowQueryDto.getPageSize();
        Page<WorkflowTaskEntityNew> page = new Page<>(pageNumber, pageSize);
        page.setOptimizeCountSql(false);
        IPage<WorkflowTaskEntityNew> workflowTaskEntityNewIPage = actHiProcinstMapper.selectworkflowtasksByUser(page, workflowQueryDto);

        //todo 进行去重
        List<WorkflowTaskEntityNew> tempRecordList = workflowTaskEntityNewIPage.getRecords();

        if (CollectionUtils.isNotEmpty(tempRecordList)) {

            tempRecordList = tempRecordList.stream().distinct().collect(Collectors.toList());
        }
        workflowTaskEntityNewIPage.setRecords(tempRecordList);
        return workflowTaskEntityNewIPage;
    }

    /*
     * 查询已办任务
     *
     * @param workflowQueryDto 查询条件
     * @return 我的任务
     */
    @Override
    public IPage<WorkflowTaskEntityNew> getCompleteTaskListByUser(WorkflowQuery workflowQueryDto) {

        String assignee = workflowQueryDto.getAssignee();

        List<String> caniteGroupList = userMapper.selectCaniteGroupList(assignee);

        StringBuilder stringBuilder = new StringBuilder();

        for (int index = 0; index < caniteGroupList.size(); index++) {
            String caniteGroup = caniteGroupList.get(index);

            if (index == caniteGroupList.size() - 1) {
                stringBuilder.append(caniteGroup);
            } else {
                stringBuilder.append(caniteGroup).append(",");
            }

        }
        workflowQueryDto.setCandidateGroups(stringBuilder.toString());

        int pageNumber = workflowQueryDto.getPageNumber();
        int pageSize = workflowQueryDto.getPageSize();
        Page<WorkflowTaskEntityNew> page = new Page<>(pageNumber, pageSize);
        page.setOptimizeCountSql(false);
        IPage<WorkflowTaskEntityNew> workflowTaskEntityNewIPage = actHiProcinstMapper.selectworkflowCompletedByUser(page, workflowQueryDto);

        return workflowTaskEntityNewIPage;
    }

    /*
     * 获取定义key
     *
     * @param procInsId
     */
    @Override
    public WorkflowDefinetion getBpmDefineBinaryFile(String procInsId) throws Exception {

        ActHiProcinst actHiProcinst = actHiProcinstMapper.selectByPrimaryKey(procInsId);

        String procDefId = actHiProcinst.getProcDefId();


        return actGeBytearrayMapper.selectByProDefId(procDefId);
    }

    /*
     * 转办理
     *
     * @param taskId         任务Id
     * @param delegationUser 转办理人
     */
    @Override
    public void tansforTask(String taskId, String delegationUser) {

        taskService.setAssignee(taskId, delegationUser);

    }


    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

        this.applicationContext = applicationContext;
    }

    static class Test {
        private String school;

        private String clasz;

        private String userName;

        public Test(String school, String clasz, String userName) {
            this.school = school;
            this.clasz = clasz;
            this.userName = userName;
        }

        public String getSchool() {
            return school;
        }

        public void setSchool(String school) {
            this.school = school;
        }

        public String getClasz() {
            return clasz;
        }

        public void setClasz(String clasz) {
            this.clasz = clasz;
        }

        public String getUserName() {
            return userName;
        }

        public void setUserName(String userName) {
            this.userName = userName;
        }


        @Override
        public int hashCode() {
            int n = 31;
            n = n * 31 + this.clasz.hashCode();
            n = n * 31 + this.school.hashCode();
            return n;
        }


        @Override
        public boolean equals(Object obj) {

            Test test = (Test) obj;
            return this.clasz.equals(test.clasz) && this.getSchool().equals(test.school);
        }

        @Override
        public String toString() {
            return "Test{" +
                    "school='" + school + '\'' +
                    ", clasz='" + clasz + '\'' +
                    ", userName='" + userName + '\'' +
                    '}';
        }
    }

    public static void main(String[] args) {

        Test test0 = new Test("海淀一小", "一年级", "jack");

        Test test1 = new Test("海淀一小", "一年级", "jack");

        Test test2 = new Test("海淀一小", "一年级", "tom");

        Test test3 = new Test("海淀一小", "二年级", "ahuang");

        List<Test> list = Lists.newArrayList();

        list.add(test0);

        list.add(test1);

        list.add(test2);

        list.add(test3);

        List<String> one = new ArrayList<>();
        one.add("1223");
        one.add("12233");

        List<String> two = new ArrayList<>();
        two.add("1223");
        two.add("12233");

        List<String> intersection = getIntersection(one, two);

        System.out.println(Arrays.asList(intersection).toString());


        list.stream().distinct().collect(Collectors.toList()).forEach(x -> System.out.println(x.toString()));


    }


    /*
     * 根据属性去重
     *
     * @param fieldExtractor
     * @param <T>
     * @return
     */
    public static <T> Predicate<T> distinctByField(Function<? super T, ?> fieldExtractor) {
        Map<Object, Boolean> map = new ConcurrentHashMap<>();

        return t -> map.putIfAbsent(fieldExtractor.apply(t), Boolean.TRUE) == null;
    }


    /*
     * 求交集
     *
     */
    public static List<String> getIntersection(List<String> listOne, List<String> listTwo) {

        List<String> intersection = listOne.stream().filter(item -> listTwo.contains(item)).collect(Collectors.toList());

        return intersection;
    }


}
